Accessibility
Home / DevNet / Dreamweaver Development Center /
DevNet
Dreamweaver Article
Icon or Spacer Icon or Spacer Icon or Spacer
Drew McLellan

Drew McLellan
Dreamweaver Fever

 
Flash Satay: Embedding Macromedia Flash While Supporting Standards


I've worked with Macromedia Flash for several years and have always been slightly dissatisfied with the markup used to embed a movie in web pages.

When I recently published a site in XHTML, my dissatisfaction with the markup grew as I realized that it simply wasn't valid in this context and that it bloated my web pages to unacceptable levels.

This situation called for a leaner, standards-compliant method of embedding Macromedia Flash movies.


The Twice-Cooked Method
Macromedia Flash has always been able to generate an HTML page that contains Macromedia Flash movies. Initially, it was a tool called AfterShock. Since the release of Macromedia Flash 4, authors could export HTML pages with embedded movies from within the Macromedia Flash authoring environment. Macromedia Flash produces markup that's the de facto standard you'll find in 99 percent of sites that use Macromedia Flash movies:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
   codebase="http://download.macromedia.com
   /pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
   width="400" height="300" id="movie" align="">
   <param name="movie" value="movie.swf">
   <embed src="movie.swf" quality="high" width="400"
      height="300" name="movie" align="" type="application/x-shockwave-flash"
      plug inspage="http://www.macromedia.com/go/getflashplayer">
</object>

As you can see, the included code is a bit of a monster. Two main tags embed the movie and require that you declare every value twice. Microsoft Internet Explorer (IE) and similar browsers primarily use one tag; browsers that consider themselves friends of Netscape use the other. I call this "The Twice Cooked Method." Here's what I mean.

The <embed> tag is not part of the XHTML specification and it will prevent your page from validating. Netscape and similar browsers use it for displaying Macromedia Flash movies. Parameters are passed within the tag as name/value attribute pairs.

Netscape created the <embed> tag as a way to embed plug-ins and players in web pages. The <embed> tag is not part of the XHTML specification, and although some browsers other than Netscape do support it, it's not compliant with standards, so you shouldn't use it.

Bye bye <embed> . . . it's been swell.

Meanwhile, although the <object> tag is part of the XHTML specification, it's badly implemented here. IE-style browsers use it to start an instance of Macromedia Flash Player and load the specified movie. The <param> tag is its counterpart, passing any number of parameters to the player once it starts.

Without the <embed> tag, you're left with the <object> tag, which is why it's prudent to understand the <object> tag's capabilities fully. The great news is that just about every popular browser supports the <object> tag in one way or another.

The <object> tag has no required attributes, but there are many you can use. Below are the more interesting ones, along with edited highlights from the W3C specification:

classid
(URI)
This attribute specifies the location of an object's implementation through a URI. You may use it with or as an alternative to the data attribute (see below), depending on the type of object involved.
codebase
(URI)
This attribute specifies the base path used to resolve relative URIs specified by the classid, data, and archive attributes. When absent, its default value is the base URI of the current document.
data
(URI)
This specifies the location of the object's data or, more generally, a serialized form of an object that can be used to recreate it.
type
(content-type)
This attribute specifies the content type for the data specified by data.
codetype
(content-type)
This attribute specifies the content type of expected data when downloading the object that classid specifies.


Other attributes allow references to archived versions, cause text to display while loading (we can do this in Macromedia Flash already), and so on. There are also the common attributes, such as width, height, id, and class. The attributes listed above, however, are particularly relevant when it comes to embedding Macromedia Flash movies.

Another useful thing I learned is that an <object> tag can contain child elements that you can then use as an alternative if the browser doesn't have the capability of displaying the object itself. In fact, this is how the undesirable nested <embed> tag works in Netscape browsers. I discuss this more later.

Cleaning up the Markup
Armed with a more thorough understanding of the markup, I wanted to test my code in various browsers. My first step was to try the Macromedia markup by stripping the <embed> tag and cleaning it up for XHTML:

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
   codebase="http://download.macromedia.com
   /pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
   width="400" height="300" />
   <param name="movie" value="movie.swf" /> 
</object>

Unfortunately, this simply doesn't work outside IE-style browsers. After a little research and some searching on Google, I discovered that the GUID I used in the classid attribute was specific to the browser's ActiveX configuration. In fact, it caused Netscape 7 and Mozilla to ignore the object entirely. The classid attribute does, however, perform an important function: It tells the browser which player to use. We can't simply get rid of it without replacing its functionality with something else.

Fortunately, the Macromedia Flash Player default configuration responds to content with an application/x-shockwave-flash MIME type. This is great because the type attribute allows you to specify a content type. Therefore, instead of using this:

classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"

You would use this:

type="application/x-shockwave-flash"

This change still doesn't permit movies to play in Netscape browsers on their own, however. So I tried something else.

Next, examine the codebase attribute, which contains a path to a copy of the Macromedia Flash plug-in on the servers at Macromedia. Using the attribute this way is incorrect, however, because any paths within it are supposed to be within the same domain—it's a security feature.

In many browsers (primarily Internet Explorer), the codebase attribute performs another function. The path contains a string on the end (#version=6,0,0,0) that specifies which plug-in version the server should deliver. If the version declared is later than the version currently installed on the user's machine, the browser will ask the user whether or not to update the player. One disadvantage of this tactic is that the codebase attribute also stops the movie from playing in Netscape and Mozilla when used in this way. That's not ideal so I won't use it. I discuss a workaround for this lost functionality more at the end of this article. By eliminating the codebase attribute, we've simplified our markup:

<object type="application/x-shockwave-flash" 
   width="400" height="300" />
   <param name="movie" value="movie.swf" /> 
</object>

If you try this code, however, it still won't load a movie in Netscape.

Having gotten this far, I worried that there was no way to use valid markup to deliver Macromedia Flash in Netscape browsers. Every time I asked this question, all of my resources confirmed that it was impossible.

So I did what I always do: I started trying crazy things.

Making Some Progress
When I tried the data attribute, I was ecstatic because movies suddenly played in Netscape and Mozilla. When I flipped back to IE, I saw that movies played there, too:

<object type="application/x-shockwave-flash" data="movie.swf" 
   width="400" height="300">
   <param name="movie" value="movie.swf" />
</object>	

After testing with larger movies, however, I noticed something was amiss. Although every other browser processed the request and played the movie correctly, Internet Explorer running on Windows was not streaming—it waited for the entire movie to download before playing it. While this is acceptable for small movies, for anything larger this lack of streaming is unacceptable. I concluded that valid markup for Macromedia Flash movies was possible but only when Microsoft had fixed their problem in Internet Explorer for Windows.

The Satay Method
A few days later I discussed this issue with Jeffrey Zeldman, explaining how I came close to a solution but hadn't quite found it. He was interested that I managed to come close, having experienced this same problem on recent projects. I started thinking and, while driving home that evening, the solution hit me.

As I said, the only problem with the code I created was that Internet Explorer for Windows didn't really stream the movie; it waited for the whole movie to download before playing it. So what if I created a very small container movie, inside of which the first frame loaded the real movie?

I tested it and it worked! It's a bit of a hack solution, but a valid and justifiable hack in my opinion. One benefit is that you don't have to create a separate container movie for each "real" movie—one smart container can work with any Macromedia Flash movie, as long as it has the same proportions.

No matter whether your movie is made from beef, chicken, or pork, you still need to skewer it and dip it in the sauce to make it work. We call this "The Satay Method."

Create the container movie.  I created a new Macromedia Flash movie and put the following ActionScript on Frame 1 right in the root of the movie:

_root.loadMovie(_root.path,0);

This instructs Macromedia Flash Player to load a movie, whose name is in the variable path on the root, into Level 0 of the current movie. All you need to do is ensure that a variable called path holds the name of the movie you want to load.

Macromedia Flash makes this easy because Macromedia Flash Player loads any name/value pairs that are passed to a movie on a query string to the movie's root. This is useful for many different applications, but in this case it means that you call the movie like this:

c.swf?path=movie.swf

The container movie is c.swf. I pass it a variable called path with a value of movie.swf. This means that the ActionScript, when evaluated, would be:

_root.loadMovie("movie.swf",0);

You can modify the behavior of the container movie to do whatever you like—as long as you keep it small. You can use GET and POST to pass variables through the container if you need to, for example. This method, however, only works well if the container movie is just a few kilobytes.

Finalize the markup.  Now all you need to do is drop a lot of attributes, add some sparkling new ones, and tidy it all up:

<object type="application/x-shockwave-flash" data="c.swf?path=movie.swf" 
   width="400" height="300">
   <param name="movie" value="c.swf?path=movie.swf" />
</object>	

So there it is—meaner, leaner, and altogether better for the environment. But what about that functionality we lost when we eliminated the codebase attribute?

The main problem with getting rid of the codebase attribute is that in Internet Explorer and similar browsers it causes the browser to prompt the user to update their Macromedia Flash plug-in if it's outdated. This is a really useful feature, as it may be the only way that most ordinary web users update their players.

My workaround is simple: Just include one sacrificial movie at the front of your site that has the codebase attribute. This must be a movie with no purpose within the site—just a 1K empty movie that causes the browser to prompt the user when they have an old version of the plug-in. While this is not the cleanest approach, it's pragmatic—and you won't lose any friends over it.

Embedding Elements in the <object> Tag
Remember the <object> tag behavior I mentioned earlier, where the browser tries to parse a child element if it can't work with the object itself? This behavior has its benefits.

If you look at the source code of the home page at macromedia.com, you will see that they serve up an alternative image if the user can't view Macromedia Flash movies. They are detecting the Macromedia Flash Player with JavaScript and then using JavaScript to dynamically write out HTML based on the detection. This is ugly, ugly, ugly.

Here's how I would do it:

<object type="application/x-shockwave-flash" data="c.swf?path=movie.swf" 
   width="400" height="300">
   <param name="movie" value="c.swf?path=movie.swf" />
   <img src="noflash.gif" width="200" height="100" alt="" />
</object>

If the browser cannot play objects with a MIME type of application/x-shockwave-flash, it will simply default to the next child element and display it (such as a simple image element, which would be acceptable for most users). If that fails, you can simply display text.

I've written this article knowing that it's simply my own findings and, thus, a work in progress. Consider that this article is similar to a scientific theory: What I state today is only proven until someone disproves it. You can follow the progress of this technique on my site, where I'll continue to research and document my findings.

This article first appeared in A List Apart magazine.

 
-----------------------------------------------------------------------------------------------------------------------------------------
 

About the author
Drew McLellan is the author of Dreamweaver MX Web Development from New Riders and is a member of the Web Standards Project's Dreamweaver Task Force, an extension writer, and an all-around Dreamweaver good guy. He runs DreamweaverFever.com and helps folks out in various support forums as a Team Macromedia volunteer. In the real world he's a feet-on-the-ground web development manager for an agency on the outskirts of London.